#include "CjTypeWrapper.h"
#include <QHash>
namespace clojure_lang {
CjTypeWrapper::CjTypeWrapper()
{
}
CjTypeWrapper::CjTypeWrapper(void *d,clojure_lang::CjTypeWrapper::CjTypeWrapperType _dtype, IPersistentMap *meta )
{
    _val = d;
    _meta = meta;
    _type = _dtype;
}

CjTypeWrapper::CjTypeWrapper(int val)
{
    _val = new int[1];
    *(int *)_val = val;
    _type = CjTypeWrapper::INT_VALUE;
}

CjTypeWrapper::CjTypeWrapper(QString val)
{
    _val = new QString(val);
    _type = CjTypeWrapper::QSTRING_VALUE;
}

CjTypeWrapper::CjTypeWrapper(QString *val)
{
    _val = new QString(*val);
    _type = CjTypeWrapper::QSTRING_VALUE;
}

CjTypeWrapper::CjTypeWrapper(QChar val)
{
    _val = new QChar(val);
    _type = CjTypeWrapper::QCHAR_VALUE;

}

CjTypeWrapper::operator int()
{
    if (_type == CjTypeWrapper::INT_VALUE) return *(int *)_val;
    if (_type == CjTypeWrapper::FLOAT_VALUE) return (float)*(int *)_val;
    if (_type == CjTypeWrapper::QSTRING_VALUE) {
        QString *val = (QString *)_val;
        bool ok;
        int retval = val->toInt(&ok);
        if (ok) return retval;
    }

    //throw CjTypeConversionException;
    return -1;
}

bool CjTypeWrapper::equals(CjObject *obj)
{
    CjTypeWrapper *tw = obj->dynamicCast<CjTypeWrapper>();
    if (tw == NULL) return false;
    if (isString() && tw->isString()) {
        if (toQString() == tw->toQString())
            return true;
    }
    if (_type != tw->typeCode()) return false;
    if (_type == CjTypeWrapper::INT_VALUE)
        if (*(int*)_val == *(int *)tw->val())
            return true;
    return false;
}

bool CjTypeWrapper::isString()
{
    if (_type == CjTypeWrapper::QSTRING_VALUE ||
        _type == CjTypeWrapper::QCHAR_VALUE)
        return true;
    return false;
}

QString CjTypeWrapper::toQString()
{
    if (_type == CjTypeWrapper::QSTRING_VALUE)
        return *(QString *)_val;
    if (_type == CjTypeWrapper::QCHAR_VALUE)
        return QString(*(QChar *)_val);
    return QString("");
}

clojure_lang::CjTypeWrapper::CjTypeWrapperType CjTypeWrapper::typeCode()
{
    return _type;
}

void *CjTypeWrapper::val()
{
    return _val;
}

int CjTypeWrapper::getHashCode()
{
    if(_type == CjTypeWrapper::INT_VALUE) return *(int *)_val;
    if(_type == CjTypeWrapper::QSTRING_VALUE) return qHash(*((QString *)_val));
    return -1;
}

CjObject *CjTypeWrapper::withMeta(IPersistentMap *meta)
{
    if (meta == _meta)
        return this;
    return CjTypeWrapper_(new CjTypeWrapper(_val, _type, meta));
}

bool CjTypeWrapper::isIndexable()
{
    if (_type == CjTypeWrapper::QSTRING_VALUE) return true;
    return false;

}

CjTypeWrapper *CjTypeWrapper::at(int idx)
{
    if (!isIndexable()) return CjTypeWrapper_(NULL);
    if (_type == CjTypeWrapper::QSTRING_VALUE)
        return CjTypeWrapper_(new CjTypeWrapper(((QString *)_val)->at(idx)));
    return CjTypeWrapper_(NULL);
}

bool CjTypeWrapper::operator==(const char *other) const {
    if (_type == CjTypeWrapper::QSTRING_VALUE)
        return *(QString *)_val == QString(other);

    return false;
 }


}
